package com.tree.thread;


import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @ClassName com.tree.thread
 * Description: <类功能描述>. <br>
 * <p>
Java程序演示如何在Java和Java中使用notify和notifyAll方法
如何通知和notifyAll方法通知线程，哪个线程被唤醒等。
 * </p>
 * @Author tree
 * @Date 4/12/24 12:06 PM
 * @Version 1.0
 */
public class NotificationTest {
    private volatile boolean go = false;

    public static void main(String args[]) throws InterruptedException {
        final NotificationTest test = new NotificationTest();

        Runnable waitTask = () -> {
            try {
                test.shouldGo();
            } catch (InterruptedException ex) {
                Logger.getLogger(NotificationTest.class.getName()).
                        log(Level.SEVERE, null, ex);
            }
            System.out.println("等待线程【"+Thread.currentThread().getName() + "】 finished Execution");
        };

        Runnable notifyTask = () -> {
            test.go();
            System.out.println("通知线程【"+Thread.currentThread().getName() + "】 finished Execution");
        };

        //will wait
        Thread t1 = new Thread(waitTask, "WT1");
        //will wait
        Thread t2 = new Thread(waitTask, "WT2");
        //will wait
        Thread t3 = new Thread(waitTask, "WT3");
        //will notify
        Thread t4 = new Thread(notifyTask,"NT1");

        //starting all waiting thread
        t1.start();
        t2.start();
        t3.start();

        //pause to ensure all waiting thread started successfully
        Thread.sleep(200);

        //starting notifying thread
        t4.start();

    }
    /**
     * wait and notify can only be called from synchronized method or bock
     */
    private synchronized void shouldGo() throws InterruptedException {
        while(go != true){
            System.out.println("等待线程【"+Thread.currentThread().getName()
                    + "】 is going to wait on this object, go="+go);
            wait(); //release lock and reacquires on wakeup
            System.out.println("等待线程【"+Thread.currentThread().getName() + "】 is woken up, go="+go);
        }
        //resetting condition
        go = false;
        System.out.println("等待线程【"+Thread.currentThread().getName() + "】执行完之后重置, go="+go);

    }

    /**
     * both shouldGo() and go() are locked on current object referenced by "this" keyword
     */
    private synchronized void go() {
        while (go == false) {
            System.out.println("通知线程【"+Thread.currentThread().getName()
                    + "】 is going to notify all or one thread waiting on this object, go="+go);

            //making condition true for waiting thread
            go = true;
            //notify(); // only one out of three waiting thread WT1, WT2,WT3 will woke up
            notifyAll(); // all waiting thread  WT1, WT2,WT3 will woke up
            System.out.println("通知线程【"+Thread.currentThread().getName()
                    + "】之后，  go="+go);
        }

    }
}
